<template>
  <div
    id="BoxPlot"
    ref="chartRef"
    class="no-padding no-margin bg-white"
    style="width: 540px; height: 540px; max-width: 540px; max-height: 540px"
  />
</template>

<script setup lang="ts">
import {
  onBeforeUnmount,
  onMounted,
  ref,
  Ref,
  computed,
  watch,
  PropType,
} from 'vue';
import { useSiteSettings } from 'src/stores/site_setting';
import { storeToRefs } from 'pinia';

import * as echarts from 'echarts/core';
import {
  DatasetComponent,
  TitleComponent,
  TooltipComponent,
  ToolboxComponent,
  GridComponent,
  LegendComponent,
} from 'echarts/components';

import { BoxplotChart, ScatterChart } from 'echarts/charts';
import { SVGRenderer } from 'echarts/renderers';

import darkTheme from 'src/css/echart_themes/dark.json';
import lightTheme from 'src/css/echart_themes/light.json';

echarts.use([
  DatasetComponent,
  TitleComponent,
  TooltipComponent,
  ToolboxComponent,
  GridComponent,
  LegendComponent,
  BoxplotChart,
  ScatterChart,
  SVGRenderer,
]);

echarts.registerTheme('myDark', darkTheme);
echarts.registerTheme('myLight', lightTheme);

// 网站的设置状态
const siteSettingStore = useSiteSettings();
const siteSettingRef = storeToRefs(siteSettingStore);

//TODO 定义组件参数
const props = defineProps({
  xlabel: {
    type: String,
    default: () => 'MNV',
  },
  qtl: {
    type: String,
    default: () => 'eQTL',
  },
  cancer: {
    type: String,
    default: () => 'ACC',
  },
  ylabel: {
    type: String,
    default: () => 'Gene',
  },
  smaples: {
    type: Array as PropType<string[]>,
    default: () => ['0', '0', '0'],
  },
  data: {
    type: Array as PropType<Array<number>>,
    default: () => [],
  },
});

const chart: Ref<echarts.ECharts | null> = ref(null);
const option = computed(() => {
  return {
    dataset: [
      {
        // prettier-ignore
        source: props.data,
      },
      {
        transform: {
          type: 'boxplot',
          config: {
            itemNameFormatter: (params) => {
              return `${params.value}\n(n=${props.smaples[params.value]})`
            }
          },
        },
      },
      {
        fromDatasetIndex: 1,
        fromTransformResult: 1,
      },
    ],
    tooltip: {
      trigger: 'item',
      axisPointer: {
        type: 'shadow',
      },
    },
    toolbox: {
      show: true,
      top: 0,
      right: 25,
      iconStyle: {
        borderWidth: 2,
      },
      emphasis: {
        iconStyle: {
          borderColor: '#26a69a',
        },
      },
      feature: {
        saveAsImage: {
          name: 'Boxplot',
          type: 'svg',
        },
      },
    },
    grid: {
      left: 80,
      right: 60,
      top: 50,
      bottom: 80,
    },
    xAxis: {
      type: 'category',
      name: props.xlabel,
      boundaryGap: true,
      nameGap: 40,
      nameLocation: 'middle',
      nameTextStyle: {
        align: 'center',
        verticalAlign: 'top',
        fontSize: 14,
        lineHeight: 18,
        fontWeight: 'bold',
        padding: [0, 0, 0, 0],
      },
      splitArea: {
        show: true,
      },
      splitLine: {
        show: false,
      },
      axisTick: {
        alignWithLabel: true,
      },
    },
    yAxis: {
      type: 'value',
      name: props.ylabel,
      splitArea: {
        show: true,
      },
      nameRotate: 90,
      nameLocation: 'middle',
      nameTextStyle: {
        align: 'center',
        verticalAlign: 'bottom',
        fontSize: 14,
        fontWeight: 'bold',
        padding: [0, 0, 40, 0],
      },
      axisTick: {
        alignWithLabel: true,
      },
    },
    series: [
      {
        name: 'boxplot',
        type: 'boxplot',
        datasetIndex: 1,
        colorBy: 'data',
        tooltip: {
          formatter: function (param) {
            return [
              'Genotype: ' + param.name.split('\n')[0],
              'Sample: ' + props.smaples[Number(param.data[0].split('\n')[0])],
              'upper: ' + Number(param.data[5]).toFixed(2),
              'Q3: ' + param.data[4].toFixed(2),
              'median: ' + param.data[3].toFixed(2),
              'Q1: ' + param.data[2].toFixed(2),
              'lower: ' + Number(param.data[1]).toFixed(2),
            ].join('<br/>');
          },
        },
      },
      {
        name: 'outlier',
        type: 'scatter',
        datasetIndex: 2,
        colorBy: 'data',
        tooltip: {
          formatter: function (param) {
            return [
              'Genotype: ' + param.data[0],
              'Value   : ' + param.data[1],
            ].join('<br/>');
          },
        },
      },
    ],
  };
});

watch(option, () => {
  chart.value?.setOption(option.value);
});

// 动态切换图的主题
const echart_theme = computed(() => {
  // return siteSettingRef.dark.value ? 'myDark' : 'myLight';
  return siteSettingRef.dark.value ? 'myDark' : 'myLight';
});
const echart_locale = computed(() => {
  return siteSettingRef.language.value;
});

const chartRef = ref<HTMLDivElement>();
const resizeHandler = () => chart.value?.resize();

const echart_init = (
  chart?: echarts.ECharts | null,
  theme: string = echart_theme.value,
  locale: string = echart_locale.value
) => {
  if (chart === undefined) {
    chart = echarts.init(chartRef.value as HTMLDivElement, theme, {
      locale: locale,
    });
    chart?.setOption(option.value);
    chart?.hideLoading();
    return chart;
  } else {
    chart?.dispose();
    let newchart = echarts.init(chartRef.value as HTMLDivElement, theme, {
      locale: locale,
    });
    newchart?.setOption(option.value);

    return newchart;
  }
};

watch(siteSettingRef.dark, () => {
  chart.value = echart_init(
    chart.value,
    echart_theme.value,
    siteSettingRef.language.value
  );
});
watch(siteSettingRef.language, () => {
  chart.value = echart_init(
    chart.value,
    echart_theme.value,
    siteSettingRef.language.value
  );
});

// 加载图表
onMounted(() => {
  chart.value = echart_init(
    chart.value,
    echart_theme.value,
    siteSettingRef.language.value
  );
  window.addEventListener('resize', resizeHandler);
});

onBeforeUnmount(() => {
  window.removeEventListener('resize', resizeHandler);
  chart.value?.dispose();
});
</script>

<style scoped lang="less"></style>
